﻿/*
    Copyright Multi-Soft co.2009 
*/
using System;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading;


namespace Rmlife.Common
{
    public delegate void ThreadCallbackHandler(string S, string s, int I, int i);

    public class Download
    {
        private string _f;
        private string _F;
        private static object _SyncLockObject = new object();
        private bool b;
        private string bs;
        private string des;
        private int i;
        private HttpWebClient x;

        public Download()
        {
            this.bs = "";
            this.b = false;
            this.i = 0;
            this.x = new HttpWebClient();
            this.des = string.Empty;
        }

        public Download(string Url, string ObjDes)
        {
            this.bs = "";
            this.b = false;
            this.i = 0;
            this.x = new HttpWebClient();
            this.des = string.Empty;
            this.FileName = Url;
            this.Des = ObjDes;
        }

        private int Digits(int n)
        {
            n = Math.Abs(n);
            n /= 10;
            int num = 1;
            while (n > 0)
            {
                n /= 10;
                num++;
            }
            return num;
        }

        public bool DownLoad()
        {
            return this.DownLoad(this.FileName, this.Des);
        }

        public bool DownLoad(string Url, string ObjDes)
        {
            this.x.DataReceive += new HttpWebClient.DataReceiveEventHandler(this.x_DataReceive);
            this.x.ExceptionOccurrs += new HttpWebClient.ExceptionEventHandler(this.x_ExceptionOccurrs);
            this._F = Url;
            try
            {
                this.x.DownloadFile(Url, ObjDes, 10);
                return true;
            }
            catch
            {
                return false;
            }
        }

        private void x_DataReceive(HttpWebClient Sender, DownLoadEventArgs e)
        {
            object obj2;
            if (!this.b)
            {
                lock ((obj2 = _SyncLockObject))
                {
                    if (!this.b)
                    {
                        this.b = true;
                    }
                }
            }
            string fileName = e.DownloadState.FileName;
            if (e.DownloadState.AttachmentName != null)
            {
                fileName = Path.GetDirectoryName(fileName) + @"\" + e.DownloadState.AttachmentName;
            }
            this._f = fileName;
            using (FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
            {
                stream.Position = e.DownloadState.Position;
                stream.Write(e.DownloadState.Data, 0, e.DownloadState.Data.Length);
                stream.Close();
            }
            string str2 = DateTime.Now.ToString();
            lock ((obj2 = _SyncLockObject))
            {
                this.i += e.DownloadState.Data.Length;
                this.bs = new string('\b', ((this.Digits(this.i) + 3) + this.Digits(Sender.FileLength)) + str2.Length);
            }
        }

        private void x_ExceptionOccurrs(HttpWebClient Sender, ExceptionEventArgs e)
        {
            Console.WriteLine(e.Exception.Message);
            new HttpWebClient().DownloadFileChunk(this._F, this._f, e.DownloadState.Position, e.DownloadState.Length);
            e.ExceptionAction = ExceptionActions.Ignore;
        }

        public string Des
        {
            get
            {
                return this.des;
            }
            set
            {
                this.des = value;
            }
        }

        public string FileName
        {
            get
            {
                return this._F;
            }
            set
            {
                this._F = value;
            }
        }
    }

    public class HttpWebClient
    {
        private int _FileLength;
        private static object _SyncLockObject = new object();
        private Uri m_baseAddress;
        private ICredentials m_credentials = CredentialCache.DefaultCredentials;
        private NameValueCollection m_requestParameters;

        public event DataReceiveEventHandler DataReceive;

        public event ExceptionEventHandler ExceptionOccurrs;

        public event ThreadProcessEventHandler ThreadProcessEnd;

        public void DownloadFile(string Address, string FileName, int ChunksCount)
        {
            int position = 0;
            int length = 0;
            string attachmentName = null;
            HttpWebResponse response = null;
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.GetUri(Address));
                response = (HttpWebResponse)request.GetResponse();
                long contentLength = response.ContentLength;
                request.Credentials = this.m_credentials;
                contentLength = ((contentLength == -1L) || (contentLength > 0x7fffffffL)) ? 0x7fffffffL : contentLength;
                int num4 = (int)contentLength;
                this._FileLength = num4;
                bool flag = (response.Headers["Accept-Ranges"] != null) & (response.Headers["Accept-Ranges"] == "bytes");
                attachmentName = response.Headers["Content-Disposition"];
                if (attachmentName != null)
                {
                    attachmentName = attachmentName.Substring(attachmentName.LastIndexOf("filename=") + 9);
                }
                else
                {
                    attachmentName = FileName;
                }
                int num5 = length;
                if (flag)
                {
                    length = num4 / ChunksCount;
                    if (length < 0x20000)
                    {
                        length = 0x20000;
                    }
                    num5 = length;
                    int num6 = 0;
                    while (num4 > length)
                    {
                        num4 -= length;
                        if (num4 < length)
                        {
                            length += num4;
                        }
                        if (num6++ > 0)
                        {
                            new Thread(new ThreadStart(new DownLoadState(Address, response.ResponseUri.AbsolutePath, FileName, attachmentName, position, length, new ThreadCallbackHandler(this.DownloadFileChunk)) { httpWebClient = this }.StartDownloadFileChunk)).Start();
                        }
                        position += length;
                    }
                    length = num5;
                    byte[] buffer = this.ResponseAsBytes(Address, response, (long)length, FileName);
                    this.OnThreadProcess(Thread.CurrentThread);
                }
            }
            catch (Exception exception)
            {
                ExceptionActions @throw = ExceptionActions.Throw;
                if (this.ExceptionOccurrs != null)
                {
                    DownLoadState downloadState = new DownLoadState(Address, response.ResponseUri.AbsolutePath, FileName, attachmentName, position, length);
                    ExceptionEventArgs e = new ExceptionEventArgs(exception, downloadState);
                    this.ExceptionOccurrs(this, e);
                    @throw = e.ExceptionAction;
                }
                if (@throw == ExceptionActions.Throw)
                {
                    if (!((exception is WebException) || (exception is SecurityException)))
                    {
                        throw new WebException("net_webclient", exception);
                    }
                    throw;
                }
            }
        }

        public void DownloadFileChunk(string Address, string FileName, int FromPosition, int Length)
        {
            HttpWebResponse response = null;
            string attachmentName = null;
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.GetUri(Address));
                request.AddRange(FromPosition);
                response = (HttpWebResponse)request.GetResponse();
                attachmentName = response.Headers["Content-Disposition"];
                if (attachmentName != null)
                {
                    attachmentName = attachmentName.Substring(attachmentName.LastIndexOf("filename=") + 9);
                }
                else
                {
                    attachmentName = FileName;
                }
                byte[] buffer = this.ResponseAsBytes(Address, response, (long)Length, FileName);
            }
            catch (Exception exception)
            {
                ExceptionActions @throw = ExceptionActions.Throw;
                if (this.ExceptionOccurrs != null)
                {
                    DownLoadState downloadState = new DownLoadState(Address, response.ResponseUri.AbsolutePath, FileName, attachmentName, FromPosition, Length);
                    ExceptionEventArgs e = new ExceptionEventArgs(exception, downloadState);
                    this.ExceptionOccurrs(this, e);
                    @throw = e.ExceptionAction;
                }
                if (@throw == ExceptionActions.Throw)
                {
                    if (!((exception is WebException) || (exception is SecurityException)))
                    {
                        throw new WebException("net_webclient", exception);
                    }
                    throw;
                }
            }
        }

        private Uri GetUri(string path)
        {
            try
            {
                Uri uri;
                if (this.m_baseAddress != null)
                {
                    uri = new Uri(this.m_baseAddress, path);
                }
                else
                {
                    uri = new Uri(path);
                }
                if (this.m_requestParameters == null)
                {
                    return uri;
                }
                StringBuilder builder = new StringBuilder();
                string str = string.Empty;
                for (int i = 0; i < this.m_requestParameters.Count; i++)
                {
                    builder.Append(str + this.m_requestParameters.AllKeys[i] + "=" + this.m_requestParameters[i]);
                    str = "&";
                }
                return new UriBuilder(uri) { Query = builder.ToString() }.Uri;
            }
            catch (UriFormatException)
            {
                return new Uri(Path.GetFullPath(path));
            }
        }

        private void OnDataReceive(DownLoadEventArgs e)
        {
            this.DataReceive(this, e);
        }

        internal void OnThreadProcess(Thread t)
        {
            if (this.ThreadProcessEnd != null)
            {
                ThreadProcessEventArgs e = new ThreadProcessEventArgs(t);
                this.ThreadProcessEnd(this, e);
            }
        }

        private byte[] ResponseAsBytes(WebResponse response)
        {
            int num;
            long contentLength = response.ContentLength;
            bool flag = false;
            if (contentLength == -1L)
            {
                flag = true;
                contentLength = 0x10000L;
            }
            byte[] buffer = new byte[(int)contentLength];
            Stream responseStream = response.GetResponseStream();
            int offset = 0;
            do
            {
                num = responseStream.Read(buffer, offset, ((int)contentLength) - offset);
                offset += num;
                if (flag && (offset == contentLength))
                {
                    contentLength += 0x10000L;
                    byte[] dst = new byte[(int)contentLength];
                    Buffer.BlockCopy(buffer, 0, dst, 0, offset);
                    buffer = dst;
                }
            }
            while (num != 0);
            responseStream.Close();
            if (flag)
            {
                byte[] buffer3 = new byte[offset];
                Buffer.BlockCopy(buffer, 0, buffer3, 0, offset);
                buffer = buffer3;
            }
            return buffer;
        }

        internal byte[] ResponseAsBytes(string RequestURL, WebResponse Response, long Length, string FileName)
        {
            string attachmentName = null;
            int position = 0;
            int length = 0;
            try
            {
                attachmentName = Response.Headers["Content-Disposition"];
                if (attachmentName != null)
                {
                    attachmentName = attachmentName.Substring(attachmentName.LastIndexOf("filename=") + 9);
                }
                long num3 = Length;
                bool flag = false;
                if (num3 == -1L)
                {
                    flag = true;
                    num3 = 0x10000L;
                }
                byte[] buffer = new byte[(int)num3];
                int srcOffset = 0;
                string str2 = Response.Headers["Content-Range"];
                if (str2 != null)
                {
                    str2 = str2.Replace("bytes ", "");
                    position = Convert.ToInt32(str2.Substring(0, str2.IndexOf("-")));
                }
                int offset = 0;
                Stream responseStream = Response.GetResponseStream();
                do
                {
                    length = responseStream.Read(buffer, offset, ((int)num3) - offset);
                    offset += length;
                    if (flag && (offset == num3))
                    {
                        num3 += 0x10000L;
                        byte[] dst = new byte[(int)num3];
                        Buffer.BlockCopy(buffer, 0, dst, 0, offset);
                        buffer = dst;
                    }
                    if (length <= 0)
                    {
                        break;
                    }
                    if (this.DataReceive != null)
                    {
                        byte[] buffer3 = new byte[length];
                        Buffer.BlockCopy(buffer, srcOffset, buffer3, 0, buffer3.Length);
                        DownLoadState downloadState = new DownLoadState(RequestURL, Response.ResponseUri.AbsolutePath, FileName, attachmentName, position, length, buffer3);
                        DownLoadEventArgs e = new DownLoadEventArgs(downloadState);
                        this.OnDataReceive(e);
                    }
                    srcOffset += length;
                    position += length;
                }
                while (length != 0);
                responseStream.Close();
                responseStream = null;
                if (flag)
                {
                    byte[] buffer4 = new byte[offset];
                    Buffer.BlockCopy(buffer, 0, buffer4, 0, offset);
                    buffer = buffer4;
                }
                return buffer;
            }
            catch (Exception exception)
            {
                ExceptionActions @throw = ExceptionActions.Throw;
                if (this.ExceptionOccurrs != null)
                {
                    DownLoadState state2 = new DownLoadState(RequestURL, Response.ResponseUri.AbsolutePath, FileName, attachmentName, position, length);
                    ExceptionEventArgs args2 = new ExceptionEventArgs(exception, state2);
                    this.ExceptionOccurrs(this, args2);
                    @throw = args2.ExceptionAction;
                }
                if (@throw == ExceptionActions.Throw)
                {
                    if (!((exception is WebException) || (exception is SecurityException)))
                    {
                        throw new WebException("net_webclient", exception);
                    }
                    throw;
                }
                return null;
            }
        }

        public byte[] UploadFile(string address, string fileName)
        {
            return this.UploadFile(address, "POST", fileName, "file");
        }

        public byte[] UploadFile(string address, string method, string fileName, string fieldName)
        {
            byte[] buffer;
            FileStream stream = null;
            try
            {
                fileName = Path.GetFullPath(fileName);
                string str = "---------------------" + DateTime.Now.Ticks.ToString("x");
                string str2 = "application/octet-stream";
                stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
                WebRequest request = WebRequest.Create(this.GetUri(address));
                request.Credentials = this.m_credentials;
                request.ContentType = "multipart/form-data; boundary=" + str;
                request.Method = method;
                string s = "--" + str + ("\r\nContent-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"") + Path.GetFileName(fileName) + "\"\r\nContent-Type: " + str2 + "\r\n\r\n";
                byte[] bytes = Encoding.UTF8.GetBytes(s);
                byte[] buffer3 = Encoding.ASCII.GetBytes("\r\n--" + str + "\r\n");
                long length = 0x7fffffffffffffffL;
                try
                {
                    length = stream.Length;
                    request.ContentLength = (length + bytes.Length) + buffer3.Length;
                }
                catch
                {
                }
                byte[] buffer4 = new byte[Math.Min(0x2000, (int)length)];
                using (Stream stream2 = request.GetRequestStream())
                {
                    int num2;
                    stream2.Write(bytes, 0, bytes.Length);
                    do
                    {
                        num2 = stream.Read(buffer4, 0, buffer4.Length);
                        if (num2 != 0)
                        {
                            stream2.Write(buffer4, 0, num2);
                        }
                    }
                    while (num2 != 0);
                    stream2.Write(buffer3, 0, buffer3.Length);
                }
                stream.Close();
                stream = null;
                WebResponse response = request.GetResponse();
                buffer = this.ResponseAsBytes(response);
            }
            catch (Exception exception)
            {
                if (stream != null)
                {
                    stream.Close();
                    stream = null;
                }
                if (!((exception is WebException) || (exception is SecurityException)))
                {
                    throw new WebException("net_webclient", exception);
                }
                throw;
            }
            return buffer;
        }

        public string UploadFileEx(string address, string method, string fileName, string fieldName)
        {
            return Encoding.ASCII.GetString(this.UploadFile(address, method, fileName, fieldName));
        }

        public string BaseAddress
        {
            get
            {
                if (this.m_baseAddress != null)
                {
                    return this.m_baseAddress.ToString();
                }
                return string.Empty;
            }
            set
            {
                if ((value == null) || (value.Length == 0))
                {
                    this.m_baseAddress = null;
                }
                else
                {
                    try
                    {
                        this.m_baseAddress = new Uri(value);
                    }
                    catch (Exception exception)
                    {
                        throw new ArgumentException("value", exception);
                    }
                }
            }
        }

        public ICredentials Credentials
        {
            get
            {
                return this.m_credentials;
            }
            set
            {
                this.m_credentials = value;
            }
        }

        public int FileLength
        {
            get
            {
                return this._FileLength;
            }
        }

        public NameValueCollection QueryString
        {
            get
            {
                if (this.m_requestParameters == null)
                {
                    this.m_requestParameters = new NameValueCollection();
                }
                return this.m_requestParameters;
            }
            set
            {
                this.m_requestParameters = value;
            }
        }

        public delegate void DataReceiveEventHandler(HttpWebClient Sender, DownLoadEventArgs e);

        public delegate void ExceptionEventHandler(HttpWebClient Sender, ExceptionEventArgs e);

        public delegate void ThreadProcessEventHandler(HttpWebClient Sender, ThreadProcessEventArgs e);
    }

    public class DownLoadEventArgs : EventArgs
    {
        private DownLoadState _DownloadState;

        public DownLoadEventArgs(DownLoadState DownloadState)
        {
            this._DownloadState = DownloadState;
        }

        public DownLoadState DownloadState
        {
            get
            {
                return this._DownloadState;
            }
        }
    }

    public class DownLoadState
    {
        private string _AttachmentName;
        private byte[] _Data;
        private string _FileName;
        private HttpWebClient _hwc;
        private int _Length;
        private int _Position;
        private string _RequestURL;
        private string _ResponseURL;
        private Thread _thread;
        private ThreadCallbackHandler _ThreadCallback;

        internal DownLoadState(string RequestURL, string ResponseURL, string FileName, string AttachmentName, int Position, int Length)
        {
            this._RequestURL = RequestURL;
            this._ResponseURL = ResponseURL;
            this._FileName = FileName;
            this._AttachmentName = AttachmentName;
            this._Position = Position;
            this._Length = Length;
        }

        internal DownLoadState(string RequestURL, string ResponseURL, string FileName, string AttachmentName, int Position, int Length, byte[] Data)
        {
            this._FileName = FileName;
            this._RequestURL = RequestURL;
            this._ResponseURL = ResponseURL;
            this._AttachmentName = AttachmentName;
            this._Position = Position;
            this._Data = Data;
            this._Length = Length;
        }

        internal DownLoadState(string RequestURL, string ResponseURL, string FileName, string AttachmentName, int Position, int Length, ThreadCallbackHandler tch)
        {
            this._RequestURL = RequestURL;
            this._ResponseURL = ResponseURL;
            this._FileName = FileName;
            this._AttachmentName = AttachmentName;
            this._Position = Position;
            this._Length = Length;
            this._ThreadCallback = tch;
        }

        internal void StartDownloadFileChunk()
        {
            if (this._ThreadCallback != null)
            {
                this._ThreadCallback(this._RequestURL, this._FileName, this._Position, this._Length);
                this._hwc.OnThreadProcess(this._thread);
            }
        }

        public string AttachmentName
        {
            get
            {
                return this._AttachmentName;
            }
        }

        public byte[] Data
        {
            get
            {
                return this._Data;
            }
        }

        public string FileName
        {
            get
            {
                return this._FileName;
            }
        }

        public HttpWebClient httpWebClient
        {
            get
            {
                return this._hwc;
            }
            set
            {
                this._hwc = value;
            }
        }

        public int Length
        {
            get
            {
                return this._Length;
            }
        }

        public int Position
        {
            get
            {
                return this._Position;
            }
        }

        public string RequestURL
        {
            get
            {
                return this._RequestURL;
            }
        }

        public string ResponseURL
        {
            get
            {
                return this._ResponseURL;
            }
        }

        internal Thread thread
        {
            get
            {
                return this._thread;
            }
            set
            {
                this._thread = value;
            }
        }
    }

    public class ExceptionEventArgs : EventArgs
    {
        private DownLoadState _DownloadState;
        private System.Exception _Exception;
        private ExceptionActions _ExceptionAction;

        internal ExceptionEventArgs(System.Exception e, DownLoadState DownloadState)
        {
            this._Exception = e;
            this._DownloadState = DownloadState;
        }

        public DownLoadState DownloadState
        {
            get
            {
                return this._DownloadState;
            }
        }

        public System.Exception Exception
        {
            get
            {
                return this._Exception;
            }
        }

        public ExceptionActions ExceptionAction
        {
            get
            {
                return this._ExceptionAction;
            }
            set
            {
                this._ExceptionAction = value;
            }
        }
    }

    public enum ExceptionActions
    {
        Throw,
        CancelAll,
        Ignore,
        Retry
    }

    public class ThreadProcessEventArgs : EventArgs
    {
        private Thread _thread;

        public ThreadProcessEventArgs(Thread thread)
        {
            this._thread = thread;
        }

        public Thread thread
        {
            get
            {
                return this._thread;
            }
        }
    }
}

